home *** CD-ROM | disk | FTP | other *** search
- /*
- * applmsg.c,v 1.0 1996/03/18 14:18:33 miksic Exp
- */
-
- /* APPLMSG.C -- LonWorks host application message handler.
- * Copyright (c) 1993 by Echelon Corporation.
- * All Rights Reserved.
- *
- * Handle application messages, network variable messages and network
- * management messages addressed to the application.
- */
-
- #include "ni_msg.h"
- #include "ni_mgmt.h"
- #include "hauif.h"
- #include <stdio.h>
- #include <fcntl.h>
- #include "conio.h"
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <unistd.h>
-
- /*************************************************************
- *
- * Declare network variable configuration table
- *
- *************************************************************/
-
- #define NUM_NVS 8
- /* Number of Network Variable table entries on this node */
-
- const int num_nvs = NUM_NVS; // for external references
- nv_struct nv_config_table[ NUM_NVS ] // configuration table
- = {
- /* selhi dir prio sello addridx auth svc trnarnd */
- { 0x3F, NV_OUT, FALSE, 0xFF, NULL_IDX, FALSE, ACKD, FALSE },
- { 0x3F, NV_OUT, FALSE, 0xFE, NULL_IDX, FALSE, ACKD, FALSE },
- { 0x3F, NV_OUT, FALSE, 0xFD, NULL_IDX, FALSE, ACKD, FALSE },
- { 0x3F, NV_OUT, FALSE, 0xFC, NULL_IDX, FALSE, ACKD, FALSE },
- { 0x3F, NV_IN , FALSE, 0xFB, NULL_IDX, FALSE, ACKD, FALSE },
- { 0x3F, NV_IN , FALSE, 0xFA, NULL_IDX, FALSE, ACKD, FALSE },
- { 0x3F, NV_IN , FALSE, 0xF9, NULL_IDX, FALSE, ACKD, FALSE },
- { 0x3F, NV_IN , FALSE, 0xF8, NULL_IDX, FALSE, ACKD, FALSE }
- }; // saved to disk
-
-
- /*************************************************************
- *
- * Declare SNVT self identification storage
- *
- *************************************************************/
-
- /* There are eight Network Variables and three message tags defined
- These are the equivalent Neuron C declarations:
-
- #pragma enable_sd_nv_names
- #pragma set_node_sd_string "Sample host application program"
-
- network output sd_string( "ASCII string output NV" )
- SNVT_str_asc NV_string_out;
- network output sd_string( "Discrete output NV" )
- SNVT_lev_disc NV_disc_out;
- network output sd_string( "Continuous output NV" )
- SNVT_lev_cont NV_cont_out;
- network output sd_string( "Floating count output NV" )
- SNVT_count_f NV_float_out;
-
- network input sd_string( "ASCII string input NV" )
- SNVT_str_asc NV_string_in;
- network input sd_string( "Discrete input NV" )
- SNVT_lev_disc NV_disc_in;
- network input sd_string( "Continuous input NV" )
- SNVT_lev_cont NV_cont_in;
- network input sd_string( "Floating count input NV" )
- SNVT_count_f NV_float_in;
-
- msg_tag tag_1;
- msg_tag tag_2;
- msg_tag tag_3;
-
- */
-
- // Network variable names
-
- #define SO_name "NV_string_out"
- #define DO_name "NV_disc_out"
- #define CO_name "NV_cont_out"
- #define FO_name "NV_float_out"
- #define SI_name "NV_string_in"
- #define DI_name "NV_disc_in"
- #define CI_name "NV_cont_in"
- #define FI_name "NV_float_in"
-
- // Self-documentation strings
-
- #define SO_doc "ASCII string output NV"
- #define DO_doc "Discrete output NV"
- #define CO_doc "Continuous output NV"
- #define FO_doc "Floating count output NV"
- #define SI_doc "ASCII string input NV"
- #define DI_doc "Discrete input NV"
- #define CI_doc "Continuous input NV"
- #define FI_doc "Floating count input NV"
-
- #define Node_doc "Sample host application program"
-
- const struct {
- snvt_struct_v0 header; // Version 0 SNVT_struct
- snvt_desc_struct string_out_desc;
- snvt_desc_struct disc_out_desc;
- snvt_desc_struct cont_out_desc;
- snvt_desc_struct float_out_desc;
- snvt_desc_struct string_in_desc;
- snvt_desc_struct disc_in_desc;
- snvt_desc_struct cont_in_desc;
- snvt_desc_struct float_in_desc;
-
- char node_doc_string[ sizeof( Node_doc ) ];
-
- snvt_ext_rec_mask string_out_mask;
- char string_out_name[ sizeof( SO_name ) ];
- char string_out_doc[ sizeof( SO_doc ) ];
- snvt_ext_rec_mask disc_out_mask;
- char disc_out_name[ sizeof( DO_name ) ];
- char disc_out_doc[ sizeof( DO_doc ) ];
- snvt_ext_rec_mask cont_out_mask;
- char cont_out_name[ sizeof( CO_name ) ];
- char cont_out_doc[ sizeof( CO_doc ) ];
- snvt_ext_rec_mask float_out_mask;
- char float_out_name[ sizeof( FO_name ) ];
- char float_out_doc[ sizeof( FO_doc ) ];
- snvt_ext_rec_mask string_in_mask;
- char string_in_name[ sizeof( SI_name ) ];
- char string_in_doc[ sizeof( SI_doc ) ];
- snvt_ext_rec_mask disc_in_mask;
- char disc_in_name[ sizeof( DI_name ) ];
- char disc_in_doc[ sizeof( DI_doc ) ];
- snvt_ext_rec_mask cont_in_mask;
- char cont_in_name[ sizeof( CI_name ) ];
- char cont_in_doc[ sizeof( CI_doc ) ];
- snvt_ext_rec_mask float_in_mask;
- char float_in_name[ sizeof( FI_name ) ];
- char float_in_doc[ sizeof( FI_doc ) ];
-
- } SNVT_info = {
- // SNVT structure
- { sizeof( SNVT_info ) >> 8, // length_hi
- sizeof( SNVT_info ) & 0xFF, // length_lo
- NUM_NVS, // num_netvars
- 0, // version
- 3 // mtag_count
- },
-
- // These SNVT descriptors have ext_rec, nv_service_type_config,
- // nv_priority_config and nv_auth_config set. In addition, the inputs
- // have nv_polled set, since the application polls them.
-
- { 0, 1, 1, 1, 0, 0, 0, 1, SNVT_str_asc }, // SNVT descriptors
- { 0, 1, 1, 1, 0, 0, 0, 1, SNVT_lev_disc },
- { 0, 1, 1, 1, 0, 0, 0, 1, SNVT_lev_cont },
- { 0, 1, 1, 1, 0, 0, 0, 1, SNVT_count_f },
- { 0, 1, 1, 1, 0, 1, 0, 1, SNVT_str_asc },
- { 0, 1, 1, 1, 0, 1, 0, 1, SNVT_lev_disc },
- { 0, 1, 1, 1, 0, 1, 0, 1, SNVT_lev_cont },
- { 0, 1, 1, 1, 0, 1, 0, 1, SNVT_count_f },
-
- Node_doc, // node self-documentation string
-
- // These extension record masks have nm and sd set
- // For Microsoft C, the initializers are hex bytes, since odd-length
- // bitfields are not allowed.
-
- #ifdef _MSC_VER
- { 0x30 },
- #else
- { 0, 0, 1, 1, 0, 0 }, // extension record mask
- #endif
- SO_name, // name
- SO_doc, // self-doc
-
- #ifdef _MSC_VER
- { 0x30 },
- #else
- { 0, 0, 1, 1, 0, 0 }, // extension record mask
- #endif
- DO_name, // name
- DO_doc, // self-doc
-
- #ifdef _MSC_VER
- { 0x30 },
- #else
- { 0, 0, 1, 1, 0, 0 }, // extension record mask
- #endif
- CO_name, // name
- CO_doc, // self-doc
-
- #ifdef _MSC_VER
- { 0x30 },
- #else
- { 0, 0, 1, 1, 0, 0 }, // extension record mask
- #endif
- FO_name, // name
- FO_doc, // self-doc
-
- #ifdef _MSC_VER
- { 0x30 },
- #else
- { 0, 0, 1, 1, 0, 0 }, // extension record mask
- #endif
- SI_name, // name
- SI_doc, // self-doc
-
- #ifdef _MSC_VER
- { 0x30 },
- #else
- { 0, 0, 1, 1, 0, 0 }, // extension record mask
- #endif
- DI_name, // name
- DI_doc, // self-doc
-
- #ifdef _MSC_VER
- { 0x30 },
- #else
- { 0, 0, 1, 1, 0, 0 }, // extension record mask
- #endif
- CI_name, // name
- CI_doc, // self-doc
-
- #ifdef _MSC_VER
- { 0x30 },
- #else
- { 0, 0, 1, 1, 0, 0 }, // extension record mask
- #endif
- FI_name, // name
- FI_doc // self-doc
- };
-
- /*************************************************************
- *
- * Declare network variable storage
- *
- *************************************************************/
-
-
- // prototypes for I/O functions
-
- void print_asc( byte * ); // print routines for SNVT values
- void print_disc( byte * );
- void print_cont( byte * );
- void print_float( byte * );
- void read_asc( byte * ); // read SNVT values from keyboard
- void read_disc( byte * );
- void read_cont( byte * );
- void read_float( byte * );
-
- network_variable nv_value_table[ NUM_NVS ] = { // RAM storage for NVs
- { 31, NV_OUT, SNVT_info.string_out_name, print_asc, read_asc },
- { 1, NV_OUT, SNVT_info.disc_out_name, print_disc, read_disc },
- { 1, NV_OUT, SNVT_info.cont_out_name, print_cont, read_cont },
- { 4, NV_OUT, SNVT_info.float_out_name, print_float,read_float },
- { 31, NV_IN, SNVT_info.string_in_name, print_asc, read_asc },
- { 1, NV_IN, SNVT_info.disc_in_name, print_disc, read_disc },
- { 1, NV_IN, SNVT_info.cont_in_name, print_cont, read_cont },
- { 4, NV_IN, SNVT_info.float_in_name, print_float,read_float }
- };
-
- // Statistics accumulators for received traffic
-
- unsigned num_messages = 0;
- unsigned num_polls = 0;
- unsigned num_updates = 0;
- unsigned long data_length = 0;
-
- boolean report_flag = TRUE; // report incoming application msgs
- boolean verbose_flag = FALSE; // display all network interface msgs
- boolean online_flag = TRUE; // This node is on-line
-
- RcvAddrDtl last_rcv_addr; // for debugging
- boolean last_rcv_auth;
-
- // Utility function to get an nv_index from a message
- // 2nd arg is pointer to pointer to next byte after nv_index
-
- word handle_nv_index( MsgData * in_data, void ** next_byte_ptr );
-
- extern boolean // define forward references
- handle_update_nv_cnfg( MsgData *, ServiceType ),
- handle_query_nv_cnfg( MsgData *, ServiceType ),
- handle_set_mode( MsgData * ),
- handle_query_SNVT( MsgData *, ServiceType ),
- handle_NV_fetch( MsgData *, ServiceType ),
- handle_netvar_msg( MsgData *, ServiceType, int in_length, boolean auth ),
- handle_explicit_msg( MsgData *, ServiceType, int in_length,
- boolean in_auth );
-
- /*************************************************************
- *
- * Handle incoming messages to this node -
- * called from main event loop when message is received
- *
- *************************************************************/
-
- boolean process_msg( ServiceType service,
- RcvAddrDtl * address,
- MsgData * in_data,
- int in_length,
- boolean in_auth ) {
-
- /* handle incoming messages addressed to this node */
- /* return TRUE if prompt should be redisplayed */
-
- last_rcv_addr = * address; // save for debug purposes
-
- switch( in_data->exp.code ) { // dispatch on message code
-
- case NM_update_nv_cnfg:
- return handle_update_nv_cnfg( in_data, service );
-
- case NM_query_nv_cnfg:
- return handle_query_nv_cnfg( in_data, service );
-
- case NM_set_node_mode:
- return handle_set_mode( in_data );
-
- case NM_query_SNVT:
- return handle_query_SNVT( in_data, service );
-
- case NM_wink:
- if( report_flag )printf( "Received Wink network mgmt msg\n" );
- printf( "\a" ); // Ding!
- return report_flag;
-
- case NM_NV_fetch:
- return handle_NV_fetch( in_data, service );
-
- default: /* handle all other messages here */
-
- if( in_data->unv.must_be_one ) // This is a net var
- return handle_netvar_msg( in_data, service, in_length, in_auth );
- // This is an explicit msg
- else return handle_explicit_msg( in_data, service, in_length, in_auth );
-
- } // end switch
- }
-
- /*************************************************************
- *
- * Handle incoming message to update NV config table
- *
- *************************************************************/
-
- boolean handle_update_nv_cnfg( MsgData * in_data, ServiceType service ) {
-
- nv_struct * nv_cnfg_ptr;
- word nv_index;
- MsgData response;
- NI_Code ni_error;
-
- // When an update_nv_cnfg message is received, the new NV config
- // is copied to the NV config table of this node
-
- nv_index = handle_nv_index( in_data, ( void * )& nv_cnfg_ptr );
- // get requested index from msg
-
- if( nv_index >= NUM_NVS ) { // too big an index
- response.exp.code = NM_update_nv_cnfg_fail;
- } else {
- response.exp.code = NM_update_nv_cnfg_succ;
- nv_config_table[ nv_index ] = * nv_cnfg_ptr;
- // save nv config table entry
- }
-
- if( service == REQUEST ) ni_error = ni_send_response( &response, 1 );
- if( report_flag ) printf(
- "Received Update NV config network mgmt msg for index %d\n",
- nv_index );
- if( service == REQUEST )
- ( void ) handle_error( ni_error, MSG_SUCCEEDS, NO_CHECK,
- "sending response" );
- return report_flag;
- }
-
- /*************************************************************
- *
- * Handle incoming message to query NV config table
- *
- *************************************************************/
-
- boolean handle_query_nv_cnfg( MsgData * in_data, ServiceType service ) {
-
- word nv_index;
- NM_query_nv_cnfg_response nv_cnfg_rsp_msg;
- int out_length;
- NI_Code ni_error;
-
- // When a query_nv_cnfg message is received, the corresponding
- // entry in the NV config table of this node is returned in a
- // response
-
- if( service != REQUEST ) return FALSE;
- nv_index = handle_nv_index( in_data, NULL );
- // get requested nv_index from message
-
- if( nv_index >= NUM_NVS ) { // too big an index
- nv_cnfg_rsp_msg.code = NM_query_nv_cnfg_fail;
- out_length = 1;
- } else {
- nv_cnfg_rsp_msg.code = NM_query_nv_cnfg_succ;
- nv_cnfg_rsp_msg.nv_cnfg = nv_config_table[ nv_index ];
- // get nv config table entry
- out_length = sizeof( NM_query_nv_cnfg_response );
- }
- ni_error = ni_send_response( ( MsgData * ) &nv_cnfg_rsp_msg, out_length );
- if( report_flag ) printf(
- "Received Query NV config network mgmt msg for index %d\n",
- nv_index );
- ( void ) handle_error( ni_error, MSG_SUCCEEDS, NO_CHECK,
- "sending response" );
- return report_flag;
- }
-
- /*************************************************************
- *
- * Handle incoming message to set the mode of this node
- *
- *************************************************************/
-
- boolean handle_set_mode( MsgData * in_data ) {
-
- extern ExpAppBuffer msg_out; /* Outgoing message buffer */
- NI_Code ni_error;
-
- // When a set_node_mode (on/off) line is received, the corresponding
- // command is sent down to the network interface
-
- online_flag = ( in_data->exp.data[ 0 ] == APPL_ONLINE );
- ni_error = ni_send_immediate( online_flag ? niONLINE : niOFFLINE );
-
- if( report_flag ) printf( "Received Set Node Mode network mgmt msg" );
- if( handle_error( ni_error, MSG_SUCCEEDS, NO_CHECK,
- "downlink mode change" ) ) return TRUE;
-
- if( report_flag )printf( " - set host node to %sline\n",
- online_flag ? "on" : "off" );
- return report_flag;
- }
-
- /*************************************************************
- *
- * Handle incoming message to query this node's SNVT info
- *
- *************************************************************/
-
- boolean handle_query_SNVT( MsgData * in_data, ServiceType service ) {
-
- int out_length;
- MsgData response;
- NI_Code ni_error;
- NM_query_SNVT_request * query_SNVT_req_msg;
- union {
- word offset;
- struct {
- byte lo;
- byte hi;
- } bytes;
- } o;
-
- if( service != REQUEST ) return FALSE;
- query_SNVT_req_msg = ( NM_query_SNVT_request * ) in_data;
-
- // get the offset in Intel byte-ordering
-
- o.bytes.hi = query_SNVT_req_msg->offset_hi;
- o.bytes.lo = query_SNVT_req_msg->offset_lo;
- out_length = query_SNVT_req_msg->count; // number of bytes requested
-
- if( o.offset + out_length > sizeof( SNVT_info ) ) {
- response.exp.code = NM_query_SNVT_fail;
- out_length = 1; // invalid request
- } else {
- response.exp.code = NM_query_SNVT_succ;
- memcpy( response.exp.data, ( byte * ) & SNVT_info + o.offset,
- out_length ); // copy data from the SNVT table to the response
- out_length++; // for the code
- }
-
- ni_error = ni_send_response( &response, out_length );
-
- if( report_flag )printf( "Received Query SNVT network mgmt msg\n" );
- ( void ) handle_error( ni_error, MSG_SUCCEEDS, NO_CHECK,
- "sending response" );
- return report_flag;
- }
-
- /*************************************************************
- *
- * Handle incoming NM message to fetch the value of an NV
- *
- *************************************************************/
-
- boolean handle_NV_fetch( MsgData * in_data, ServiceType service ) {
-
- word nv_index;
- MsgData response;
- int out_length;
- network_variable * nv_value_ptr;
- NI_Code ni_error;
-
- if( service != REQUEST ) return FALSE;
-
- // When an NV_fetch message is received, value is fetched
- nv_index = handle_nv_index( in_data, NULL );
- // get requested NV index from msg
- if( nv_index >= NUM_NVS ) {
- response.exp.code = NM_NV_fetch_fail;
- out_length = 1;
- } else { // construct a response
- nv_value_ptr = & nv_value_table[ nv_index ];
- response.exp.code = NM_NV_fetch_succ;
- response.exp.data[ 0 ] = nv_index;
- memcpy( &response.exp.data[ 1 ], nv_value_ptr->data,
- nv_value_ptr->size );
- out_length = nv_value_ptr->size + 2; // add code and index
- }
-
- ni_error = ni_send_response( &response, out_length );
- if( report_flag ) printf(
- "Received NV fetch network mgmt msg for %s\n", nv_value_ptr->name );
- ( void ) handle_error( ni_error, MSG_SUCCEEDS, NO_CHECK,
- "sending response" );
- return report_flag;
- }
-
- /*************************************************************
- *
- * match_nv_cnfg - find an entry in NV config table
- * returns index of entry, or -1 if not found
- *
- *************************************************************/
-
- static int match_nv_cnfg( UnprocessedNV * in_nv ) {
-
- nv_struct * nv_cnfg_ptr;
- int nv_index;
- nv_cnfg_ptr = nv_config_table; // point to NV config table
-
- for( nv_index = 0; nv_index < NUM_NVS; nv_index++ ) {
- if( in_nv->NV_selector_lo == nv_cnfg_ptr->selector_lo
- && in_nv->NV_selector_hi == nv_cnfg_ptr->selector_hi
- && in_nv->direction == nv_cnfg_ptr->direction )
- return nv_index;
- nv_cnfg_ptr++; // next config table entry
- }
- return -1; // not found - return error
- }
-
- /*************************************************************
- *
- * Handle incoming NV messages to this node
- *
- *************************************************************/
-
- boolean handle_netvar_msg( MsgData * in_data,
- ServiceType service,
- int in_length,
- boolean in_auth ) {
-
- nv_struct * nv_cnfg_ptr;
- network_variable * nv_value_ptr;
- int nv_index;
- int out_length;
- MsgData response;
- NI_Code ni_error;
- boolean auth_OK;
-
- // Find this NV in the NV config table
- nv_index = match_nv_cnfg( &in_data->unv );
-
- if( nv_index >= 0 ) { // found the NV
- nv_cnfg_ptr = &nv_config_table[ nv_index ];
- // point to NV config table
- nv_value_ptr = & nv_value_table[ nv_index ];
- // point to NV data table
- auth_OK = in_auth || !nv_cnfg_ptr->auth;
- // Message is authentic if it was authenticated by the Neuron or
- // authentication is not configured for this NV
- }
-
- if( service == REQUEST ) { // it's an NV poll
- response.unv.NV_selector_hi = in_data->unv.NV_selector_hi;
- response.unv.direction = ~ in_data->unv.direction;
- // reverse the direction bit to send it back
- response.unv.NV_selector_lo = in_data->unv.NV_selector_lo;
- response.unv.must_be_one = 1;
-
- if( nv_index >= 0 && auth_OK && online_flag ) {
- // there was a match
- memcpy( response.unv.data, nv_value_ptr->data, nv_value_ptr->size );
- // fetch the value
- out_length = nv_value_ptr->size + 2; // including selector
- num_polls++;
- } else out_length = 2; // no match or off-line, respond anyway
-
- ni_error = ni_send_response( &response, out_length );
- // add the selector size
- if( report_flag && nv_index >= 0 ) printf( "Received poll for %s\n",
- nv_value_ptr->name );
-
- ( void ) handle_error( ni_error, MSG_SUCCEEDS, NO_CHECK,
- "sending response" );
- return report_flag;
- }
-
- // Come here if it's not a poll
- in_length -= 2; // subtract out the selector size
-
- if( nv_index < 0 // NV not found
- || !auth_OK // failed authentication
- || in_length != nv_value_ptr->size ) // size mismatch
- return FALSE; // done if not a valid update
-
- memcpy( nv_value_ptr->data, in_data->unv.data, in_length );
- // update NV
- num_updates++;
- if( report_flag )
- printf( "Updated %s with : ", nv_value_ptr->name );
- nv_value_ptr->print_func( nv_value_ptr->data );
-
- return report_flag;
- }
-
- /*************************************************************
- *
- * Internal routine to update the value of a network variable
- *
- *************************************************************/
-
- static void update_nv_value( int nv_index,
- byte * data,
- int size ) {
-
- network_variable * nv_value_ptr;
-
- nv_value_ptr = & nv_value_table[ nv_index ]; // point to NV data table
- if( size != nv_value_ptr->size ) return;
- // Reject update if wrong size
- memcpy( nv_value_ptr->data, data, size ); // update the NV value
-
- num_updates++;
- printf( "Updated %s with : ", nv_value_ptr->name );
- nv_value_ptr->print_func( nv_value_ptr->data );
- }
-
- /*************************************************************
- *
- * Handle incoming NV poll responses
- *
- *************************************************************/
-
- void handle_netvar_poll_response(
- UnprocessedNV * in_nv,
- int in_length,
- int nv_index ) {
-
- nv_struct * nv_cnfg_ptr;
-
- if( report_flag )printf( "Received network variable poll response\n" );
- // Match on direction and selector bits ( not the first bit )
-
- nv_cnfg_ptr = &nv_config_table[ nv_index ]; // point to NV config table
-
- if( in_nv->NV_selector_lo != nv_cnfg_ptr->selector_lo ) return;
- if( in_nv->NV_selector_hi != nv_cnfg_ptr->selector_hi ) return;
- if( in_nv->direction != nv_cnfg_ptr->direction ) return;
-
- update_nv_value( nv_index, in_nv->data, in_length - 2 );
- // data size is msg size less selector size
- }
-
- /*************************************************************
- *
- * Handle incoming explicit messages to this node
- *
- *************************************************************/
-
- boolean handle_explicit_msg( MsgData * in_data,
- ServiceType service,
- int in_length,
- boolean in_auth ) {
-
- extern const char * svc_table[ ]; // strings for service type
- byte response;
- NI_Code ni_error;
-
- num_messages++;
- data_length += ( in_length - 1 ); // not counting code
-
- // if node is off-line and a request message is received
- if( service == REQUEST && !online_flag ) {
- response = ( in_data->exp.code >= NA_foreign_msg ) ?
- NA_foreign_offline : NA_appl_offline;
-
- // return off-line response
- ni_error = ni_send_response( ( MsgData * ) &response, 1 );
- ( void ) handle_error( ni_error, MSG_SUCCEEDS, NO_CHECK,
- "sending response" );
- }
- if( report_flag ) {
-
- printf( "Received explicit application message\n" );
- printf( "Service type %s\n", svc_table[ service ] );
- printf( "Message code = 0x%x\n", in_data->exp.code );
- printf( "Authentication %s\n", in_auth ? "on" : "off" );
- printf( "Length = %d\n", in_length );
- }
- return report_flag;
- }
-
- /*************************************************************
- *
- * Utility function to return a possibly escaped
- * NV index from a message. Used by query/update NV config
- * and NV fetch network management messages
- *
- *************************************************************/
-
- word handle_nv_index( MsgData * in_data, void ** next_byte_ptr ) {
- word nv_index;
-
- byte * msg_data_ptr = in_data->exp.data;
- // point to first data byte of message
-
- nv_index = * msg_data_ptr ++; // get first byte of message
-
- if( nv_index == 0xFF ) { // this is an escape sequence
- // convert Neuron long to Intel word
- swab( ( char * )msg_data_ptr++, ( char * )&nv_index, 2 );
- msg_data_ptr++; // point past the long
- }
- if( next_byte_ptr ) * next_byte_ptr = msg_data_ptr;
- // return pointer to byte after the index
- return nv_index;
- }
-
- /*************************************************************
- *
- * Command to report incoming traffic statistics
- *
- *************************************************************/
-
- void traffic( void ) {
-
- printf( "Appl msgs received \t= %u\n", num_messages );
- printf( "Msg data received \t= %lu bytes\n", data_length );
- printf( "NV updates received \t= %u\n", num_updates );
- printf( "NV polls received \t= %u\n", num_polls );
- printf( "Clearing message and NV accumulators\n" );
-
- data_length = num_messages = num_polls = num_updates = 0;
- }
-
- /*
- ****************************************************************************
- *
- * exit_func(). Process exit command from the keyboard, store NV config
- *
- ****************************************************************************
- */
-
- void exit_func( void ) {
-
- int fd;
- unsigned byte_count;
-
- fd = creat( "NVCONFIG.TBL", 0644 );
- if( fd < 0 ) {
- printf( "Unable to open network variable config file\n" );
- exit( 1 );
- }
- byte_count = write( fd, nv_config_table, sizeof( nv_config_table ) );
- if( byte_count != sizeof( nv_config_table ) ) {
- printf( "Unable to write to network variable config file\n" );
- close( fd );
- exit( 1 );
- }
- close( fd );
- ni_close( );
- printf("Leaving the Host Application program.\n");
- exit( 0 );
- }
-
- /*************************************************************
- *
- * Load NV config table from disk
- *
- *************************************************************/
-
- void load_NV_config( void ) { // called from main() startup code
- int fd;
- unsigned byte_count;
-
- fd = open( "NVCONFIG.TBL", O_RDONLY );
- if( fd < 0 ) return; // No file yet
- byte_count = read( fd, nv_config_table, sizeof( nv_config_table ) );
- if( byte_count == sizeof( nv_config_table ) ) { // success
- printf( "Network variable config table loaded\n" );
- close( fd );
- return;
- }
- printf( "Unable to load NV config table from file\n" );
- close( fd );
- }
-
- /*************************************************************
- *
- * get_nv_index - prompt user to enter NV index
- *
- *************************************************************/
-
- int get_nv_index( boolean in_only ) { // returns -1 if invalid
-
- static const char * dir_string[ 2 ] = { "IN ", "OUT" };
- int nv_index;
- network_variable * nv_value_ptr;
-
- nv_value_ptr = nv_value_table;
- // list all the network variables - menu label is index+1
-
- for( nv_index = 0; nv_index < NUM_NVS; nv_index++, nv_value_ptr++ ) {
- if( in_only && nv_value_ptr->direction != NV_IN ) continue;
- // don't list if not asked for
- printf( "%d. \t%s\t%s\t", nv_index + 1,
- dir_string[ nv_value_ptr->direction ], nv_value_ptr->name );
- nv_value_ptr->print_func( nv_value_ptr->data ); // print value
- }
-
- nv_index = get_integer( "Enter NV number :", 0 ) - 1;
- // If user enters 0 (the default), return error
-
- if( nv_index >= NUM_NVS || nv_index < 0 ) {
- printf( "Invalid NV number\n" );
- return -1;
- }
-
- nv_value_ptr = &nv_value_table[ nv_index ];
- if( in_only && nv_value_ptr->direction != NV_IN ) {
- printf( "Invalid direction\n" );
- return -1;
- }
- return nv_index;
- }
-
- /*************************************************************
- *
- * Command to poll an input network variable
- *
- *************************************************************/
-
- void NV_poll( void ) {
-
- int nv_index, ta_nv_index;
- NI_Code ni_error;
- ComplType completion;
- int num_responses;
- int in_length;
- SendAddrDtl out_addr;
- MsgData in_data, out_data;
- nv_struct * nv_cnfg_ptr;
- network_variable * nv_value_ptr;
-
- printf( "Which input network variable do you wish to poll?\n" );
- nv_index = get_nv_index ( TRUE ); // get index of NV from user
- if( nv_index < 0 || ! online_flag ) return;
- // all done if NV not found, or node is off-line
- nv_cnfg_ptr = &nv_config_table[ nv_index ]; // point to cnfg table
-
- // make an outgoing request message to poll the NV
- out_data.unv.direction = NV_OUT; // to match the receiver(s)
- out_data.unv.NV_selector_hi = nv_cnfg_ptr->selector_hi;
- out_data.unv.NV_selector_lo = nv_cnfg_ptr->selector_lo;
- out_data.unv.must_be_one = 1;
-
- if( nv_cnfg_ptr->addr_index != NULL_IDX ) { // NV is bound
-
- out_addr.im.type = IMPLICIT;
- out_addr.im.msg_tag = nv_cnfg_ptr->addr_index;
- // For implicit addressing, use configured address table entry
-
- ni_error = ni_send_msg_wait(
- REQUEST,
- & out_addr, // destination address
- & out_data,
- 2, // size of selector
- nv_cnfg_ptr->priority,
- nv_cnfg_ptr->auth,
- & completion,
- & num_responses,
- NULL, // response address
- & in_data, // first response data
- & in_length ); // input length
-
- if( handle_error( ni_error, completion, NO_CHECK,
- "polling NV" ) ) return;
-
- if( num_responses ) for( ;; ) { // handle responses, if any
-
- handle_netvar_poll_response( & in_data.unv, in_length,
- nv_index );
- // update the value if a valid response
-
- if( !--num_responses ) break;
-
- ni_error = ni_get_next_response( // get another, if a group
- NULL, // response address
- & in_data, // response data
- & in_length );
- if( handle_error( ni_error, completion, NO_CHECK,
- "polling NV" ) ) return;
- }
- }
- if( !nv_cnfg_ptr->turnaround ) return;
- // all done if not a turnaround
-
- // get the value of the matching output
- ta_nv_index = match_nv_cnfg( &out_data.unv );
- if( ta_nv_index < 0 ) return; // no match
-
- nv_value_ptr = &nv_value_table[ ta_nv_index ]; // point to NV value table
- update_nv_value( nv_index, nv_value_ptr->data, nv_value_ptr->size );
- }
-
- /*************************************************************
- *
- * Command to update a network variable
- *
- *************************************************************/
-
- void NV_update( void ) {
-
- network_variable * nv_value_ptr;
- nv_struct * nv_cnfg_ptr;
- int nv_index;
- int out_length;
- NI_Code ni_error;
- ComplType completion;
- SendAddrDtl out_addr;
- MsgData out_data;
-
- printf( "Which network variable do you wish to update?\n" );
- nv_index = get_nv_index ( FALSE ); // get NV index from user
- if( nv_index < 0 ) return;
-
- nv_value_ptr = &nv_value_table[ nv_index ]; // point to value table
- printf( "Enter data for %s :", nv_value_ptr->name );
- nv_value_ptr->read_func( nv_value_ptr->data ); // get NV data from user
-
- if( nv_value_ptr->direction == NV_IN || ! online_flag ) return;
- // all done if an input or node is not on-line
-
- // make an outgoing NV update message
-
- nv_cnfg_ptr = &nv_config_table[ nv_index ]; // point to config table
-
- out_data.unv.direction = NV_IN; // to match the receiver
- out_data.unv.NV_selector_hi = nv_cnfg_ptr->selector_hi;
- out_data.unv.NV_selector_lo = nv_cnfg_ptr->selector_lo;
- out_data.unv.must_be_one = 1;
-
- out_length = nv_value_ptr->size;
- memcpy( out_data.unv.data, nv_value_ptr->data, out_length );
- out_length += 2; // add selector size to send
-
- if( nv_cnfg_ptr->addr_index != NULL_IDX ) { // NV is bound
-
- out_addr.im.type = IMPLICIT; // use the address table for dest
- out_addr.im.msg_tag = nv_cnfg_ptr->addr_index;
-
- ni_error = ni_send_msg_wait(
- nv_cnfg_ptr->service, // use configured service type
- & out_addr, // destination address
- & out_data,
- out_length, // including selector
- nv_cnfg_ptr->priority,
- nv_cnfg_ptr->auth,
- & completion,
- NULL, // num_responses
- NULL, // response address
- NULL, // response data
- NULL ); // input length
- ( void )handle_error( ni_error, completion, NO_CHECK,
- "updating NV" );
- }
- if( !nv_cnfg_ptr->turnaround ) return; // all done if not a turnaround
- // find the matching input NV
- ( void ) handle_netvar_msg( & out_data, UNACKD, out_length, TRUE );
- }
-
-
- /*************************************************************
- *
- * User interface routines for SNVTs
- *
- *************************************************************/
-
- void print_asc( byte * data ) { // print a value of type SNVT_str_asc
- printf( "\"%s\"\n", data );
- }
-
- void print_cont( byte * data ) { // print a value of type SNVT_lev_cont
- printf( "%g percent\n", * data / 2.0 );
- }
-
- void print_disc( byte * data ) { // print a value of type SNVT_lev_disc
-
- switch ( * data ) {
- case 0: printf( "OFF\n" ); return;
- case 1: printf( "LOW\n" ); return;
- case 2: printf( "MEDIUM\n" ); return;
- case 3: printf( "HIGH\n" ); return;
- case 4: printf( "ON\n" ); return;
- default: printf( "Invalid discrete value %d\n", * data );
- }
- }
-
- void print_float( byte * data ) { // print a value of type SNVT_xxx_f
- union {
- float intel_float;
- byte neuron_float[ 4 ];
- } swapper;
- int i;
-
- for( i = 3; i >= 0; i-- )
- swapper.neuron_float[ i ] = * data++; // reverse byte order
- printf( "%.5G\n", swapper.intel_float );
- }
-
- void read_asc( byte * data ) { // read a value of type SNVT_str_asc
- char input_buf[ 80 ];
-
- gets( input_buf );
- memset( data, 0, 31 ); // null it out
- strncpy( ( char * )data, input_buf, 31 ); // copy up to 31 bytes
- }
-
- void read_disc( byte * data ) { // read a value of type SNVT_lev_disc
- char ch;
- for( ;; ) {
- printf( "\nO(F)F, (L)OW, (M)EDIUM, (H)IGH or O(N) :" );
- ch = getche( );
- switch( toupper( ch ) ) {
- case 'F': * data = 0; break;
- case 'L': * data = 1; break;
- case 'M': * data = 2; break;
- case 'H': * data = 3; break;
- case 'N': * data = 4; break;
- default : printf( " -- invalid choice" ); continue;
- }
- printf( "\n" );
- return;
- }
- }
-
- void read_cont( byte * data ) { // read a value of type SNVT_lev_cont
- * data = 2 * get_integer( "(percent) ", * data / 2 );
- }
-
- void read_float( byte * data ) { // read a value of type SNVT_xxx_f
- union {
- float intel_float;
- byte neuron_float[ 4 ];
- } swapper;
- int i;
- char input_buf[ 80 ];
-
- for( ;; ) {
- gets( input_buf );
- if( sscanf( input_buf, "%g", &swapper.intel_float ) == 1 ) break;
- printf( "Invalid floating point data\n" );
- }
-
- for( i = 3; i >= 0; i-- )
- * data ++ = swapper.neuron_float[ i ]; // reverse byte order
- }
-